using System.Collections;
using System.Collections.Generic;
using JKFrame;
using Map.config;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Serialization;

public class MapGenerator
{
    //整个地图都是方的 都是地图块
    private int mapSize; //地图尺寸  一行或一列有多少个地图块
    private int mapChunkSize; //一个地图块有多少个格子
    private float cellSize; //一个格子多少米

    private float noiseLacunarity; // 噪音间隙
    private int mapSeed; // 地图种子
    private int spawnSeed; // 随时地图对象的种子
    private float marshLimit; // 沼泽的边界
    private MapGrid mapGrid; // 地图逻辑网格、顶点数据
    private Material mapMaterial;
    private Material marshMaterial;

    private Texture2D forestTexutre;
    private Texture2D[] marshTextures;
    private MapConfig mapConfig; //地图配置
    
    private Mesh chunkMesh;//地图块 Mesh

    public MapGenerator(int mapSize, int mapChunkSize, float cellSize, Material mapMaterial, float noiseLacunarity,
        int mapSeed, int spawnSeed, float marshLimit, Texture2D forestTexutre, Texture2D[] marshTextures,
        MapConfig mapConfig)
    {
        this.mapSize = mapSize;
        this.mapChunkSize = mapChunkSize;
        this.cellSize = cellSize;
        this.mapMaterial = mapMaterial;
        this.noiseLacunarity = noiseLacunarity;
        this.mapSeed = mapSeed;
        this.spawnSeed = spawnSeed;
        this.marshLimit = marshLimit;
        this.forestTexutre = forestTexutre;
        this.marshTextures = marshTextures;
        this.mapConfig = mapConfig;
    }


    /// <summary>
    /// 生成地图 通用数据
    /// </summary>
    public void GenerateMapData()
    {
        //随机地图种子
        Random.InitState(mapSeed);
        //生成全地图噪声图
        var noiseMap = GenerateNoiseMap(mapSize * mapChunkSize, mapSize * mapChunkSize, noiseLacunarity);
        //生成全地图网格
        mapGrid = new MapGrid(mapSize * mapChunkSize, mapSize * mapChunkSize, cellSize);
        mapGrid.GenerateMapGrid();
        //计算贴图索引 
        mapGrid.CalculateCellTextureIndex(noiseMap, marshLimit);
        // 初始化一个默认材质的尺寸
        mapMaterial.mainTexture = forestTexutre;
        mapMaterial.SetTextureScale("_MainTex", new Vector2(cellSize * mapChunkSize, cellSize * mapChunkSize));
        //实例化一个沼泽材质
        marshMaterial = new Material(mapMaterial);
        marshMaterial.SetTextureScale("_MainTex", Vector2.one);
        chunkMesh = GenerateMapMesh(mapChunkSize, mapChunkSize, cellSize);
        
        // 使用种子来进行随机生成地图上的对象
        Random.InitState(spawnSeed);
    }

    public MapChunkController GenerateMapChunk(Vector2Int index, Transform transform)
    {
        //生成地图块物体
        var mapChunkObj = new GameObject("Chunk_" + index.ToString());
        var mapChunk = mapChunkObj.AddComponent<MapChunkController>();
        //生成 mesh
        mapChunkObj.AddComponent<MeshFilter>().mesh = chunkMesh;

        mapChunkObj.AddComponent<MeshCollider>();
        //生产地图块贴图
        Texture2D mapTexture;
        this.StartCoroutine(
            GenerateMapTexture(index, ((tex, isAllForest) =>
            {
                if (isAllForest)
                {
                    mapChunkObj.AddComponent<MeshRenderer>().material = mapMaterial;
                }
                else
                {
                    mapTexture = tex;
                    var material = new Material(marshMaterial)
                    {
                        mainTexture = tex
                    };
                    mapChunkObj.AddComponent<MeshRenderer>().material = material;
                }
            })));
        // 确定坐标
        Vector3 position = new Vector3(index.x * mapChunkSize * cellSize, 0, index.y * mapChunkSize * cellSize);
        mapChunk.transform.position = position;
        mapChunkObj.transform.SetParent(transform);

        // 生成场景物体
        List<MapChunkObjectModel> mapChunkObjectModelList = GenerateSpawnMapObject(index);
        mapChunk.Init(index, position + new Vector3((mapChunkSize * cellSize) / 2, 0, (mapChunkSize * cellSize) / 2),
            mapChunkObjectModelList);
        return mapChunk;
    }

    /// <summary>
    /// 生成地图贴图
    /// </summary>
    /// <param name="cellTextureIndex">顶点 索引</param>
    /// <param name="groundTextuure"></param>
    /// <param name="marshTexture"></param>
    private IEnumerator GenerateMapTexture(Vector2Int chunkIndex, System.Action<Texture2D, bool> callBack)
    {
        // float startTime = Time.realtimeSinceStartup;

        // 当前地块的偏移量 找到这个地图块具体的每一个格子
        int cellOffsetX = chunkIndex.x * mapChunkSize + 1;
        int cellOffsetY = chunkIndex.y * mapChunkSize + 1;
        bool isAllForest = true;
        // 检查是否只有森林类型的格子
        for (int y = 0; y < mapChunkSize; y++)
        {
            if (isAllForest == false) break;
            for (int x = 0; x < mapChunkSize; x++)
            {
                MapCell cell = mapGrid.GetCell(x + cellOffsetX, y + cellOffsetY);
                if (cell != null && cell.TextureIndex != 0)
                {
                    isAllForest = false;
                    break;
                }
            }
        }

        Texture2D mapTexture = null;
        // 有沼泽的情况
        if (!isAllForest)
        {
            // 贴图都是矩形
            int textureCellSize = forestTexutre.width;
            // 整个地图块的宽高,正方形
            int textureSize = mapChunkSize * textureCellSize;
            mapTexture = new Texture2D(textureSize, textureSize, TextureFormat.RGB24, false);

            // 遍历每一个格子
            for (int y = 0; y < mapChunkSize; y++)
            {
                // 一帧只执行一列 只绘制一列的像素
                yield return null;
                // 像素偏移量
                int pixelOffsetY = y * textureCellSize;
                for (int x = 0; x < mapChunkSize; x++)
                {
                    int pixelOffsetX = x * textureCellSize;
                    int textureIndex = mapGrid.GetCell(x + cellOffsetX, y + cellOffsetY).TextureIndex - 1;
                    // 绘制每一个格子内的像素
                    // 访问每一个像素点
                    for (int y1 = 0; y1 < textureCellSize; y1++)
                    {
                        for (int x1 = 0; x1 < textureCellSize; x1++)
                        {
                            // 设置某个像素点的颜色
                            // 确定是森林还是沼泽
                            // 这个地方是森林 ||
                            // 这个地方是沼泽但是是透明的，这种情况需要绘制groundTexture同位置的像素颜色
                            if (textureIndex < 0)
                            {
                                Color color = forestTexutre.GetPixel(x1, y1);
                                mapTexture.SetPixel(x1 + pixelOffsetX, y1 + pixelOffsetY, color);
                            }
                            else
                            {
                                // 是沼泽贴图的颜色
                                Color color = marshTextures[textureIndex].GetPixel(x1, y1);
                                if (color.a < 1f)
                                {
                                    mapTexture.SetPixel(x1 + pixelOffsetX, y1 + pixelOffsetY,
                                        forestTexutre.GetPixel(x1, y1));
                                }
                                else
                                {
                                    mapTexture.SetPixel(x1 + pixelOffsetX, y1 + pixelOffsetY, color);
                                }
                            }
                        }
                    }
                }
            }

            mapTexture.filterMode = FilterMode.Point;
            mapTexture.wrapMode = TextureWrapMode.Clamp;
            mapTexture.Apply();
            
        }

        callBack?.Invoke(mapTexture, isAllForest);
        // float endTime = Time.realtimeSinceStartup;
        // JKLog.Log("Function took: " + (endTime - startTime) + " seconds");
    }

    /// <summary>
    /// 生成 mesh
    /// </summary>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <param name="cellSize"></param>
    /// <returns></returns>
    private Mesh GenerateMapMesh(int width, int height, float cellSize)
    {
        Mesh mesh = new Mesh();
        mesh.vertices = new[]
        {
            new Vector3(0, 0, 0),
            new Vector3(0, 0, height * cellSize),
            new Vector3(width * cellSize, 0, height * cellSize),
            new Vector3(width * cellSize, 0, 0),
        };
        mesh.triangles = new[]
        {
            0, 1, 2,
            0, 2, 3,
        };
        mesh.uv = new[]
        {
            new Vector2(0, 0),
            new Vector2(0, 1),
            new Vector2(1, 1),
            new Vector2(1, 0),
        };
        mesh.RecalculateNormals();
        return mesh;
    }

    /// <summary>
    /// 生成噪声图 为顶点服务的
    /// </summary>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <param name="lacunarity"></param>
    /// <param name="seed"></param>
    /// <returns></returns>
    public float[,] GenerateNoiseMap(int width, int height, float lacunarity)
    {
        var noiseMap = new float[width - 1, height - 1];
        var offsetW = Random.Range(-10000f, 10000f);
        var offsetH = Random.Range(-10000f, 10000f);
        for (int h = 0; h < noiseMap.GetLength(0); h++)
        {
            for (int w = 0; w < noiseMap.GetLength(1); w++)
            {
                noiseMap[w, h] = Mathf.PerlinNoise(h * lacunarity + offsetH, w * lacunarity + offsetW);
            }
        }

        return noiseMap;
    }

    public List<GameObject> mapObjects = new List<GameObject>();

    // private List<MapChunkObjectModel> GenerateSpawnMapObject(MapGrid grid, MapConfig spawnConfig, int spawnSeed)
    private List<MapChunkObjectModel> GenerateSpawnMapObject(Vector2Int index)
    {
        List<MapChunkObjectModel> mapChunkObjectModelsList = new List<MapChunkObjectModel>();
        
        // int mapHeight = mapGrid.MapHeight;
        // int mapWidth = mapGrid.MapWidth;

        // 遍历地图顶点
        for (int x = 1 ; x < mapChunkSize; x++)
        {
            for (int y = 1 ; y < mapChunkSize; y++)
            {
                MapVertex mapVertex = mapGrid.GetVertex(x + index.x * mapChunkSize , y + index.y * mapChunkSize);
                // 根据概率配置随机
                List<MapObjectSpawnConfigModel> configModels = mapConfig.SpawnConfigs[mapVertex.VertexType];

                // 我们确保整个配置概率值合为100
                int randValue = Random.Range(1, 101); // 实际命中数字是从1~100 
                float temp = 0;
                int spawnConfigIndex = 0; // 最终要生成的物品

                // 30 20 50
                for (int i = 0; i < configModels.Count; i++)
                {
                    temp += configModels[i].Probability;
                    if (randValue < temp)
                    {
                        // 命中
                        spawnConfigIndex = i;
                        break;
                    }
                }

                // 确定到底生成什么物品
                MapObjectSpawnConfigModel spawnModel = configModels[spawnConfigIndex];
                if (spawnModel.isEmpty == false)
                {
                    // 实例化物品
                    Vector3 position = mapVertex.Position + new Vector3(Random.Range(-cellSize / 2, cellSize / 2), 0,
                        Random.Range(-cellSize / 2, cellSize / 2));
                    mapChunkObjectModelsList.Add(new MapChunkObjectModel()
                    {
                        Position = position,
                        Prefab = spawnModel.prefab,
                    });
                    // GameObject go = GameObject.Instantiate(spawnModel.Prefab, mapVertex.Position + offset, Quaternion.identity, transform);
                    // mapObjects.Add(go);
                }
            }
        }

        return mapChunkObjectModelsList;
    }
}